package {{.packageName}}

import (
	"context"
    "errors"
	{{.imports}}

    "github.com/golifes/go-sqlbuilder"
    "google.golang.org/grpc/status"
)

const (
    ExistErrCode           = 10 //已存在
	CreateErrCode          = 11 //添加失败
	BatchCreateErrCode     = 12
	DetailErrCode         = 13  //查询详情失败
	FindErrCode            = 14  //查询列表失败
	UpdateErrCode          = 15  //更新失败
	BatchUpdateErrCode     = 16  //批量更新失败
	DeleteSoftErrCode      = 17  //删除失败(软)
	BatchDeleteSoftErrCode = 18  //批量删除失败(软)
	DeleteErrCode          = 19  //删除失败
	BatchDeleteErrCode     = 20 //批量删除失败
	DeleteCacheErrCode      = 21 //删除缓存失败
	BatchDeleteCacheErrCode = 22
	CreateCacheErrCode = 23
	FindCacheErrCode   = 24
	LimitMaxErrCode    = 25 //操作超过最大限制数
)


type Obj *model.{{.originPackageName}}
type Objs []*model.{{.originPackageName}}

func conn(svc *svc.ServiceContext) Inter {
	return svc.Entity.Conn{{.originPackageName}}
}

func getObject(ctx context.Context, svc *svc.ServiceContext, id any, builder *sqlbuilder.SelectBuilder) (obj Obj, err error) {
	db := conn(svc)
	if id != nil {
		obj, err = db.Retrieve(ctx, id)
	} else {
		obj, err = db.PartialRetrieve(ctx, *builder)
	}
	return
}

func GetObject(ctx context.Context, svc *svc.ServiceContext, id any, builder *sqlbuilder.SelectBuilder) (obj Obj, err error) {
	if obj, err = getObject(ctx, svc, id, builder); err != nil {
		return nil, status.Errorf(DetailErrCode, err.Error())
	}
	return
}
func Goroutines(ctx context.Context, n int) *pool.ContextPool {
	return pool.New().WithMaxGoroutines(int(n/50) + 1).WithContext(ctx)
}

func Find(ctx context.Context, svc *svc.ServiceContext, builder *sqlbuilder.SelectBuilder) (obj Objs, err error) {
	obj, err = conn(svc).Find(ctx, *builder)
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return nil, status.Errorf(FindErrCode, err.Error())
	}
	return obj, nil
}

func Ids(ctx context.Context, svc *svc.ServiceContext, builder *sqlbuilder.SelectBuilder) (ids []any, err error) {
	ids, err = conn(svc).Ids(ctx, *builder)
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return nil, status.Errorf(FindErrCode, err.Error())
	}
	return ids, nil
}

func Count(ctx context.Context, svc *svc.ServiceContext, builder *sqlbuilder.SelectBuilder, field string) (count int64, err error) {
	count, err = conn(svc).Count(ctx, *builder, field)
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return 0, status.Errorf(FindErrCode, err.Error())
	}
	return count, nil
}
func Create(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, obj Obj) (affect int64, err error) {
	affect, err = conn(svc).Create(ctx, session, obj)
	if err != nil {
		return affect, status.Errorf(CreateErrCode, err.Error())
	}
	return affect, nil
}
func Update(ctx context.Context, svc *svc.ServiceContext, next bool, session sqlx.Session, obj Obj) (affect int64, err error) {
	if !next {
		return 0, status.Error(UpdateErrCode, model.ErrNotModified.Error())
	}
	affect, err = conn(svc).UpdateWithVersion(ctx, session, obj)
	if err != nil {
		return affect, status.Errorf(UpdateErrCode, err.Error())
	}
	return
}

func Delete(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, id any) (affect int64, err error) {
	affect, err = conn(svc).Delete(ctx, session, id)
	if err != nil {
		return affect, status.Errorf(DeleteErrCode, err.Error())
	}
	return
}
func DeleteCacheById(ctx context.Context, svc *svc.ServiceContext, id any) (err error) {
	err = conn(svc).DeleteCacheById(ctx, id)
	if err != nil {
		return status.Errorf(DeleteCacheErrCode, err.Error())
	}
	return
}
func BatchDeleteCache(ctx context.Context, svc *svc.ServiceContext, ids []any) (err error) {
	p := Goroutines(ctx, len(ids))
	for _, id := range ids {
		id := id
		p.Go(func(ctx context.Context) error {
			if err := DeleteCacheById(ctx, svc, id); err != nil {
				return err
			}
			//<-ctx.Done()
			return nil
		})
	}
	if err := p.Wait(); err != nil {
		return status.Errorf(BatchDeleteCacheErrCode, err.Error())
	}
	return nil
}
func DeleteCache(ctx context.Context, svc *svc.ServiceContext, key string) (err error) {
	err = conn(svc).DeleteCache(ctx, key)
	if err != nil {
		return status.Errorf(DeleteCacheErrCode, err.Error())
	}
	return
}

func BatchDeleteSoft(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, objs Objs) (err error) {
	p := Goroutines(ctx, len(objs))
	for _, obj := range objs {
		obj := obj
		p.Go(func(ctx context.Context) error {
			if _, err := DeleteSoft(ctx, svc, session, obj); err != nil {
				return err
			}
			//<-ctx.Done()
			return nil
		})
	}
	if err := p.Wait(); err != nil {
		return status.Errorf(BatchDeleteSoftErrCode, err.Error())
	}
	return nil
}

func DeleteSoft(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, obj Obj) (affect int64, err error) {
	obj.DeletedStatus = constantx.IsDeleted
	obj.DeletedTime = convertx.Unix()
	affect, err = conn(svc).UpdateWithVersion(ctx, session, obj)
	if err != nil {
		return affect, status.Errorf(DeleteSoftErrCode, err.Error())
	}
	return
}

func PerformBulkCreate(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, objs Objs) map[any]error {
	return conn(svc).PerformBulkCreate(ctx, session, objs)
}

func BulkCreate(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, objs Objs) (err error) {
	return conn(svc).BulkCreate(ctx, session, objs)
}
func PerformBulkUpdate(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, objs Objs) map[any]error {
	return conn(svc).PerformBulkUpdate(ctx, session, objs)
}
func BulkUpdate(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, builder sqlbuilder.UpdateBuilder) (err error) {
	return conn(svc).BulkUpdate(ctx, session, builder)
}

func PerformBulkDelete(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, ids []any) map[any]error {
	return conn(svc).PerformBulkDelete(ctx, session, ids)
}

func BulkDelete(ctx context.Context, svc *svc.ServiceContext, session sqlx.Session, builder sqlbuilder.DeleteBuilder) error {
	return conn(svc).BulkDelete(ctx, session, builder)
}

func GetObjectOrValid(ctx context.Context, svc *svc.ServiceContext, id any) (obj Obj, err error) {
	if obj, err = getObject(ctx, svc, id, nil); err != nil {
		return nil, status.Errorf(DetailErrCode, err.Error())
	} else if obj.OpenStatus != constantx.IsOpen || obj.DeletedStatus != constantx.IsNotDeleted {
		return nil, status.Errorf(DetailErrCode, model.ErrNotAvailable.Error())
	}
	return
}

// Validate 创建对象之前检查这个瓜对象是否存在
func Validate(ctx context.Context, svc *svc.ServiceContext, builder *sqlbuilder.SelectBuilder) (obj Obj, err error) {
	obj, err = getObject(ctx, svc, nil, builder)
	if err != nil && !errors.Is(err, model.ErrNotFound) { //拦截not found的error
		return nil, status.Errorf(CreateErrCode, err.Error())
	} else if obj != nil {
		return nil, status.Errorf(ExistErrCode, model.ErrExist.Error())
	}
	return nil, nil
}

func SetCache(ctx context.Context, svc *svc.ServiceContext, key string, value any, expire int64) error {
	if err := conn(svc).SetCache(ctx, key, value, expire); err != nil {
		return status.Errorf(CreateCacheErrCode, err.Error())
	}
	return nil
}
func GetCache(ctx context.Context, svc *svc.ServiceContext, key string, value any) error {
	if err := conn(svc).GetCache(ctx, key, value); err != nil {
		return status.Errorf(FindCacheErrCode, err.Error())
	}
	return nil
}
func GetPrimaryKey(ctx context.Context, svc *svc.ServiceContext, id any) string {
	return conn(svc).PrimaryKey(id)
}
